using System;
using System.IO;
using System.Web;
using System.Collections;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Drawing.Imaging;

namespace BEGalleryExtension
{
    public class PhotoHandler : IHttpHandler
    {
        public void ProcessRequest(HttpContext context)
        {
            string basePath = context.Server.MapPath("~/App_Data/gallery/");
            context.Response.ContentType = "image/jpeg";
            int ID = 0;
            Int32.TryParse(context.Request.QueryString["id"], out ID);
            PhotoSize size = (PhotoSize)Enum.Parse(typeof(PhotoSize), context.Request.QueryString["size"], true);

            PhotoInformation pinfo = new PhotoInformation();
            string file = pinfo.getPhotoLocationFromID(ID);

            if (string.IsNullOrEmpty(file))
                return;

            FileInfo finfo = new FileInfo(Path.Combine(basePath, file));
            if (!finfo.Exists)
                return;

            long quality = 95L;
            if (size == PhotoSize.Small)
                quality = 75L;

            ImageCodecInfo jpegCodec = GetEncoderInfo("image/jpeg");
            Encoder jpegEncoder = Encoder.Quality;
            EncoderParameters jpegEncoderParameters = new EncoderParameters(1);
            EncoderParameter jpegEncoderQuality = new EncoderParameter(jpegEncoder, quality);
            jpegEncoderParameters.Param[0] = jpegEncoderQuality;

            byte[] bytes = (byte[])context.Cache["Photo-" + ID + "-" + size];
            if (bytes == null)
            {
                using (Image img = new Bitmap(finfo.FullName))
                {
                    if (size == PhotoSize.Original)
                    {
                        img.Save(context.Response.OutputStream, jpegCodec, jpegEncoderParameters);
                        context.Cache.Insert("Photo-" + ID + "-" + size, ConvertImageToByteArray(img, ImageFormat.Jpeg));
                    }
                    else
                    {
                        Size imgSize = getSize(size, img);
                        using (Image thumbnail = new Bitmap(img, imgSize))
                        {
                            using (Graphics g = Graphics.FromImage(thumbnail))
                            {
                                g.InterpolationMode = InterpolationMode.HighQualityBicubic;
                                g.CompositingQuality = CompositingQuality.HighQuality;
                                g.SmoothingMode = SmoothingMode.HighQuality;
                                g.DrawImage(img, new Rectangle(0, 0, thumbnail.Size.Width, thumbnail.Size.Height));
                                thumbnail.Save(context.Response.OutputStream, jpegCodec, jpegEncoderParameters);
                                context.Cache.Insert("Photo-" + ID + "-" + size, ConvertImageToByteArray(thumbnail, ImageFormat.Jpeg));
                            }
                        }
                    }
                }
            }
            else
            {
                context.Response.BinaryWrite(bytes);
            }
        }

        private ImageCodecInfo GetEncoderInfo(String mimeType)
        {
            int j;
            ImageCodecInfo[] encoders;
            encoders = ImageCodecInfo.GetImageEncoders();
            for (j = 0; j < encoders.Length; ++j)
            {
                if (encoders[j].MimeType == mimeType)
                    return encoders[j];
            }
            return null;
        }

        private static byte[] ConvertImageToByteArray(Image imageToConvert, ImageFormat formatOfImage)
        {
            byte[] ret;

            using (MemoryStream ms = new MemoryStream())
            {
                imageToConvert.Save(ms, formatOfImage);
                ret = ms.ToArray();
            }

            return ret;
        }

        private Image ConvertByteArrayToImage(byte[] myByteArray)
        {
            if (myByteArray == null)
                return null;

            Image newImage = null;
            using (MemoryStream ms = new MemoryStream(myByteArray, 0, myByteArray.Length))
            {
                ms.Write(myByteArray, 0, myByteArray.Length);
                newImage = Image.FromStream(ms, true);
            }

            return newImage;
        }

        private Size getSize(PhotoSize size, Image img)
        {
            int h = img.Height;
            int w = img.Width;
            int b = h > w ? h : w;
            int maxDim = b;

            switch (size)
            {
                case PhotoSize.Small:
                    maxDim = 200;
                    break;

                case PhotoSize.Medium:
                    maxDim = 320;
                    break;

                case PhotoSize.Large:
                    maxDim = 640;
                    break;

                case PhotoSize.ExtraLarge:
                    maxDim = 800;
                    break;
            }

            double per = (b > maxDim) ? (maxDim * 1.0) / b : 1.0;
            h = (int)(h * per);
            w = (int)(w * per);

            Size imgSize = new Size(w, h);
            return imgSize;
        }

        public bool IsReusable
        {
            get { return true; }
        }
    }
}
